package nevo.pkgs.expr;

import java.util.*;

import org.lsmp.djep.vectorJep.*;
import org.lsmp.djep.vectorJep.values.*;
import org.nfunk.jep.*;

public class RealFunction
{
	protected String expression;
	
	protected int inputDimension;
	protected int outputDimension;
	
	public RealFunction()
	{
		inputDimension = 1;
		outputDimension = 1;
	}
	
	public void setOutputDimension(int d) { outputDimension = d; }
	public int getOutputDimension() { return outputDimension; }
		
	public void setInputDimension(int d) { inputDimension = d; }
	public int getInputDimension() { return inputDimension; }
	
	public void setExpression(String expr) { expression = expr; }
	public String getExpression() { return expression; }
	
	public Object evaluate(Map<String, Object> input) throws Exception
	{
		JEP parser = makeParser();
		for (Map.Entry<String,Object> entry : input.entrySet()) {
			String key = entry.getKey();
			Object oval = entry.getValue();
						
			if (parser.getVar(key) != null) parser.removeVariable(key);
			
			if ((oval instanceof Double) || (oval instanceof Integer)) {
				parser.addVariable(key, oval);				
			} else if (oval instanceof Double[]) {
				Double[] vval = (Double []) oval;
				if (vval.length != inputDimension) {
					throw new Exception("Input vector length doesn't match specified dimension of input!");
				}
				MVector v = new MVector(inputDimension);
				for (int k = 0; k < inputDimension; k++)  v.setEle(k, vval[k]);
				parser.addVariable(key, v);
			} else if (oval instanceof Integer[]) {
				Integer[] vval = (Integer []) oval;
				if (vval.length != inputDimension) {
					throw new Exception("Input vector length doesn't match specified dimension of input!");
				}
				MVector v = new MVector(inputDimension);
				for (int k = 0; k < inputDimension; k++)  v.setEle(k, vval[k]);
				parser.addVariable(key, v);
			} else {
				throw new Exception("Unknown variable class: " + oval.getClass().getName());
			}
		}
		
		Node function = parser.parse(expression);
		Object output = parser.evaluate(function);
		
		return output;
	}
	
	private final JEP makeParser()
	{	
		JEP parser;
		if ((inputDimension + outputDimension) == 2) {
			parser = new JEP();
		} else {
			parser = new VectorJep();
		}
		parser.addStandardConstants();
		parser.addStandardFunctions();
		parser.setImplicitMul(false);
		parser.setAllowUndeclared(true);
		
		return parser;
	}

}
